#ifndef LS_H
#define LS_H

#ifdef __cplusplus
extern "C" {
#endif

#include <time.h>
#include <stdint.h>

// 跨平台类型适配
#ifdef _WIN32
#include <windows.h>
#include <basetsd.h>
#include <sys/types.h>

// 补充 Windows 缺失的 POSIX 类型
#ifndef _SSIZE_T_DEFINED
typedef SSIZE_T ssize_t;
#define _SSIZE_T_DEFINED
#endif

#ifndef _NLINK_T_DEFINED
typedef unsigned short nlink_t;
#define _NLINK_T_DEFINED
#endif

#ifndef _UID_T_DEFINED
typedef unsigned int uid_t;
#define _UID_T_DEFINED
#endif

#ifndef _GID_T_DEFINED
typedef unsigned int gid_t;
#define _GID_T_DEFINED
#endif

// 权限类型
typedef DWORD ls_mode_t;

#else
#include <sys/types.h>
typedef mode_t ls_mode_t;
#endif

// 文件类型
typedef enum {
    LS_FILE,    // 普通文件
    LS_DIR,     // 目录
    LS_LINK     // 符号链接
} ls_filetype;

// 文件信息结构体
typedef struct {
    char name[256];               // 文件名
    ls_filetype type;             // 文件类型
    off_t size;                   // 文件大小
    time_t mtime;                 // 最后修改时间
    ls_mode_t mode;               // 权限类型
#ifdef _WIN32
    DWORD attributes;             // Windows 文件属性
#endif
} ls_fileinfo;

// 选项结构体
typedef struct {
    int all;           // 显示隐藏文件（-a）
    int long_format;   // 长格式显示（-l）
    int human_readable;// 人类可读大小（-h）
    int reverse;       // 反向排序（-r）
    int sort_time;     // 按修改时间排序（-t）
} ls_options;

// 函数声明
int ls(const char* path, const ls_options* options, 
       ls_fileinfo* files, int maxcount);
char* ls_format_long(const ls_fileinfo* info, const ls_options* options, 
                     char* buffer, int bufsize);
void ls_cleanup(void);

#ifdef __cplusplus
}
#endif

#endif // LS_H

// 实现部分（LS_IMPLEMENTATION 激活）
#ifdef LS_IMPLEMENTATION

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

#ifdef _WIN32
#include <shlwapi.h>
#include <direct.h>
#pragma comment(lib, "shlwapi.lib")

// 路径配置
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#define getcwd _getcwd

// 权限位定义
#define LS_IRUSR 0x0100
#define LS_IWUSR 0x0080
#define LS_IXUSR 0x0040
#define LS_IRGRP 0x0020
#define LS_IROTH 0x0004
#define LS_IFDIR 0x4000
#define LS_IFREG 0x8000

#else
// Unix-like 复用系统权限位
#define LS_IRUSR S_IRUSR
#define LS_IWUSR S_IWUSR
#define LS_IXUSR S_IXUSR
#define LS_IRGRP S_IRGRP
#define LS_IROTH S_IROTH
#define LS_IFDIR S_IFDIR
#define LS_IFREG S_IFREG
#endif

// 内部辅助函数声明
static void get_permission_string(ls_mode_t mode, char* buf);
static char* human_readable_size(off_t size, char* buffer, int bufsize);
static int compare_files(const void* a, const void* b);
static int compare_files_by_time(const void* a, const void* b);
static void reverse_array(void* array, size_t count, size_t element_size);

// 修复：人类可读大小转换（确保正确返回转换后的字符串）
static char* human_readable_size(off_t size, char* buffer, int bufsize) {
    const char* units[] = {"B", "K", "M", "G", NULL};
    int unit = 0;
    double size_val = (double)size;

    // 目录大小显示为空
    if (size == 0) {
        snprintf(buffer, bufsize, "        ");
        return buffer;
    }

    // 计算单位
    while (size_val >= 1024.0 && units[unit+1] != NULL) {
        size_val /= 1024.0;
        unit++;
    }

    // 确保格式正确（例如 "83.8K" 而不是 "83.8 K"）
    snprintf(buffer, bufsize, "%.1f%s", size_val, units[unit]);
    return buffer;
}

// 生成权限字符串
static void get_permission_string(ls_mode_t mode, char* buf) {
    buf[0] = (mode & LS_IRUSR) ? 'r' : '-';
    buf[1] = (mode & LS_IWUSR) ? 'w' : '-';
    buf[2] = (mode & LS_IXUSR) ? 'x' : '-';
    buf[3] = (mode & LS_IRGRP) ? 'r' : '-';
    buf[4] = '-';
    buf[5] = '-';
    buf[6] = (mode & LS_IROTH) ? 'r' : '-';
    buf[7] = '-';
    buf[8] = '-';
    buf[9] = '\0';
}

// 按文件名排序
static int compare_files(const void* a, const void* b) {
    const ls_fileinfo* fa = (const ls_fileinfo*)a;
    const ls_fileinfo* fb = (const ls_fileinfo*)b;

    if (fa->type != fb->type) {
        return (fa->type == LS_DIR) ? -1 : 1;
    }
    return strcmp(fa->name, fb->name);
}

// 按修改时间排序
static int compare_files_by_time(const void* a, const void* b) {
    const ls_fileinfo* fa = (const ls_fileinfo*)a;
    const ls_fileinfo* fb = (const ls_fileinfo*)b;

    if (fa->type != fb->type) {
        return (fa->type == LS_DIR) ? -1 : 1;
    }
    return (fa->mtime > fb->mtime) ? -1 : 1;
}

// 反向数组
static void reverse_array(void* array, size_t count, size_t element_size) {
    char* arr = (char*)array;
    char* temp = (char*)malloc(element_size);
    if (!temp) return;

    for (size_t i = 0; i < count / 2; i++) {
        size_t j = count - 1 - i;
        memcpy(temp, &arr[i * element_size], element_size);
        memcpy(&arr[i * element_size], &arr[j * element_size], element_size);
        memcpy(&arr[j * element_size], temp, element_size);
    }

    free(temp);
}

// 核心函数实现
int ls(const char* path, const ls_options* options,
       ls_fileinfo* files, int maxcount) {
    if (!files || maxcount <= 0) return -1;

    ls_options default_opt = {0};
    if (!options) {
        options = &default_opt;
    }

    // 获取目录路径
    char dirpath[PATH_MAX];
    if (path) {
        strncpy(dirpath, path, PATH_MAX - 1);
        dirpath[PATH_MAX - 1] = '\0';
    } else {
        if (!getcwd(dirpath, PATH_MAX)) {
            fprintf(stderr, "getcwd failed: %d\n", GetLastError());
            return -1;
        }
    }

    int file_count = 0;
    memset(files, 0, maxcount * sizeof(ls_fileinfo));

#ifdef _WIN32
    // Windows 核心实现
    WIN32_FIND_DATA find_data;
    HANDLE h_find;
    char search_path[PATH_MAX];

    snprintf(search_path, PATH_MAX, "%s\\*", dirpath);
    h_find = FindFirstFile(search_path, &find_data);

    if (h_find == INVALID_HANDLE_VALUE) {
        fprintf(stderr, "FindFirstFile failed: %d\n", GetLastError());
        return -1;
    }

    do {
        // 跳过隐藏/系统文件（-a 除外）
        if (!options->all && (find_data.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))) {
            continue;
        }
        if (file_count >= maxcount) break;

        ls_fileinfo* curr_file = &files[file_count];
        strncpy(curr_file->name, find_data.cFileName, sizeof(curr_file->name) - 1);
        curr_file->attributes = find_data.dwFileAttributes;

        // 判断文件类型并设置大小（修复：正确获取文件大小）
        if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            curr_file->type = LS_DIR;
            curr_file->size = 0;  // 目录大小为0
        } else if (find_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
            curr_file->type = LS_LINK;
            curr_file->size = find_data.nFileSizeLow;
        } else {
            curr_file->type = LS_FILE;
            curr_file->size = find_data.nFileSizeLow;  // 正确获取文件大小
        }

        // 转换时间为 time_t
        FILETIME ft = find_data.ftLastWriteTime;
        SYSTEMTIME st;
        FileTimeToSystemTime(&ft, &st);

        struct tm tm_time = {0};
        tm_time.tm_sec = st.wSecond;
        tm_time.tm_min = st.wMinute;
        tm_time.tm_hour = st.wHour;
        tm_time.tm_mday = st.wDay;
        tm_time.tm_mon = st.wMonth - 1;
        tm_time.tm_year = st.wYear - 1900;
        tm_time.tm_isdst = -1;

        curr_file->mtime = mktime(&tm_time);
        if (curr_file->mtime == -1) curr_file->mtime = 0;

        // 设置权限模式
        curr_file->mode = (curr_file->type == LS_DIR) ? 
            (LS_IFDIR | LS_IRUSR | LS_IWUSR | LS_IRGRP | LS_IROTH) : 
            (LS_IFREG | LS_IRUSR | LS_IWUSR | LS_IRGRP | LS_IROTH);

        file_count++;
    } while (FindNextFile(h_find, &find_data) != 0);

    if (GetLastError() != ERROR_NO_MORE_FILES) {
        fprintf(stderr, "FindNextFile failed: %d\n", GetLastError());
        FindClose(h_find);
        return -1;
    }
    FindClose(h_find);
#else
    // Unix-like 实现
    DIR* dir = opendir(dirpath);
    if (!dir) { perror("opendir failed"); return -1; }

    struct dirent* entry;
    while ((entry = readdir(dir)) != NULL) {
        if (!options->all && entry->d_name[0] == '.') continue;
        if (file_count >= maxcount) break;

        ls_fileinfo* curr_file = &files[file_count];
        strncpy(curr_file->name, entry->d_name, sizeof(curr_file->name) - 1);

        char fullpath[PATH_MAX];
        snprintf(fullpath, PATH_MAX, "%s/%s", dirpath, entry->d_name);
        struct stat st;

        if (lstat(fullpath, &st) == 0) {
            curr_file->size = st.st_size;
            curr_file->mtime = st.st_mtime;
            curr_file->mode = (ls_mode_t)st.st_mode;
            curr_file->type = S_ISDIR(st.st_mode) ? LS_DIR : 
                             S_ISLNK(st.st_mode) ? LS_LINK : LS_FILE;
        }

        file_count++;
    }
    closedir(dir);
#endif

    // 排序
    if (options->sort_time) {
        qsort(files, file_count, sizeof(ls_fileinfo), compare_files_by_time);
    } else {
        qsort(files, file_count, sizeof(ls_fileinfo), compare_files);
    }
    if (options->reverse) {
        reverse_array(files, file_count, sizeof(ls_fileinfo));
    }

    return file_count;
}

// 修复：长格式格式化（确保-h选项生效）
char* ls_format_long(const ls_fileinfo* info, const ls_options* options,
                     char* buffer, int bufsize) {
    if (!info || !options || !buffer || bufsize <= 0) return NULL;

    char perm[10], size_str[32], time_str[32];
    get_permission_string(info->mode, perm);

    // 修复：强制检查human_readable选项并处理大小显示
    if (options->human_readable) {
        // 人类可读模式：调用转换函数
        human_readable_size(info->size, size_str, sizeof(size_str));
        // 确保宽度一致（8个字符）
        snprintf(size_str, sizeof(size_str), "%8s", size_str);
    } else {
        // 普通模式：显示原始大小
        if (info->type == LS_DIR) {
            snprintf(size_str, sizeof(size_str), "%8s", "");
        } else {
            snprintf(size_str, sizeof(size_str), "%8lld", (long long)info->size);
        }
    }

    // 处理时间显示
    struct tm* tm_ptr = localtime(&info->mtime);
    if (tm_ptr) {
        strftime(time_str, sizeof(time_str), "%b %d %H:%M", tm_ptr);
    } else {
        strcpy(time_str, "Unknown   ");
    }

    // 拼接结果（Windows 版本）
#ifdef _WIN32
    snprintf(buffer, bufsize, "%c%s %s %s %s",
             (info->type == LS_DIR) ? 'd' : (info->type == LS_LINK) ? 'l' : '-',
             perm, size_str, time_str, info->name);
#else
    // Unix-like 版本
    char user[32] = "???";
    char group[32] = "???";
    struct passwd* pwd = getpwuid(info->uid);
    if (pwd) strncpy(user, pwd->pw_name, sizeof(user)-1);
    struct group* grp = getgrgid(info->gid);
    if (grp) strncpy(group, grp->gr_name, sizeof(group)-1);

    snprintf(buffer, bufsize, "%c%s %2d %-8s %-8s %s %s %s",
             (info->type == LS_DIR) ? 'd' : (info->type == LS_LINK) ? 'l' : '-',
             perm, (int)info->nlink, user, group, size_str, time_str, info->name);
#endif

    return buffer;
}

// 资源清理
void ls_cleanup(void) {
#ifdef __unix__
    endpwent();
    endgrent();
#endif
}

#endif // LS_IMPLEMENTATION

// 命令行工具（LS_MAIN 激活）
#ifdef LS_MAIN
#include <stdio.h>

static void print_usage(const char* prog_name) {
    fprintf(stderr, "用法: %s [选项] [目录]\n", prog_name);
    fprintf(stderr, "选项:\n");
    fprintf(stderr, "  -a        显示所有文件（含隐藏/系统文件）\n");
    fprintf(stderr, "  -l        长格式显示（权限、大小、时间）\n");
    fprintf(stderr, "  -h        人类可读大小（如 1.2K）\n");
    fprintf(stderr, "  -r        反向排序\n");
    fprintf(stderr, "  -t        按修改时间排序\n");
    fprintf(stderr, "  --help    显示帮助\n");
    fprintf(stderr, "选项可叠加使用，如: ls -lh 或 ls -alht\n");
}

// 解析选项（支持叠加选项）
static void parse_options(int argc, char* argv[], ls_options* options, const char** target_dir) {
    *target_dir = "."; // 默认目录

    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            // 处理长选项 --help
            if (strcmp(argv[i], "--help") == 0) {
                print_usage(argv[0]);
                exit(0);
            }

            // 处理短选项（支持叠加，如 -lh）
            for (int j = 1; argv[i][j] != '\0'; j++) {
                switch (argv[i][j]) {
                    case 'a': options->all = 1; break;
                    case 'l': options->long_format = 1; break;
                    case 'h': options->human_readable = 1; break;
                    case 'r': options->reverse = 1; break;
                    case 't': options->sort_time = 1; break;
                    default:
                        fprintf(stderr, "未知选项: -%c\n", argv[i][j]);
                        exit(1);
                }
            }
        } else {
            // 非选项参数视为目录
            *target_dir = argv[i];
        }
    }
}

int main(int argc, char* argv[]) {
    ls_options options = {0};
    const char* target_dir;

    // 解析命令行选项（支持叠加选项）
    parse_options(argc, argv, &options, &target_dir);

    // 获取目录内容
    ls_fileinfo files[1024];
    int count = ls(target_dir, &options, files, 1024);
    if (count < 0) {
        fprintf(stderr, "获取目录失败: %s\n", target_dir);
        return 1;
    }

    // 输出结果
    if (options.long_format) {
        for (int i = 0; i < count; i++) {
            char buf[256];
            // 强制传入options确保-h生效
            ls_format_long(&files[i], &options, buf, sizeof(buf));
            printf("%s\n", buf);
        }
    } else {
        for (int i = 0; i < count; i++) {
            char size_buf[16] = "";
            if (options.human_readable && files[i].type != LS_DIR) {
                human_readable_size(files[i].size, size_buf, sizeof(size_buf));
                printf("%-16s(%-6s)  ", files[i].name, size_buf);
            } else {
                printf("%-16s%s  ", files[i].name, (files[i].type == LS_DIR) ? "/" : "");
            }
            if ((i + 1) % 3 == 0) {
                printf("\n");
            }
        }
        if (count > 0) printf("\n");
    }

    ls_cleanup();
    return 0;
}
#endif // main 实现